package com.ruoyi.result.common;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Image;
import com.ruoyi.common.config.AliOSSConfig;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.result.Result;
import com.ruoyi.result.utils.AliOSSUtils;
import com.ruoyi.system.domain.result_entity.fileInfo;
import com.ruoyi.system.service.FileInfoService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
@RestController
@Api(tags = "文件上传")
@CrossOrigin
public class UploadController {

    @Autowired
    private AliOSSUtils aliOSSUtils;

    @Autowired
    private AliOSSConfig aliOSSConfig;


    @Autowired
    private FileInfoService fileInfoService;
    @GetMapping("/upload/pdfImages")
    @ApiOperation("获取PDF转换后的图片URL列表")
    public AjaxResult getPdfImages(@RequestParam("filePath") String filePath) {
        try {
            // 对前端编码后的filePath进行解码（处理特殊字符）
            String decodedFilePath = URLDecoder.decode(filePath, StandardCharsets.UTF_8.name());

            // 处理完整URL的情况，提取相对路径部分
            if (decodedFilePath.startsWith("http")) {
                // 使用正则表达式匹配pdf-images/后面的UUID部分
                Pattern pattern = Pattern.compile("pdf-images/[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}/");
                Matcher matcher = pattern.matcher(decodedFilePath);
                if (matcher.find()) {
                    decodedFilePath = matcher.group(0);
                } else {
                    // 返回错误信息，使用明确的错误码
                    return AjaxResult.error(500, "URL格式不正确，无法提取PDF路径");
                }
            }

            // 确保路径以斜杠结尾
            if (!decodedFilePath.endsWith("/")) {
                decodedFilePath += "/";
            }

            // 查询数据库（使用解码后的原始路径）
            fileInfo fileInfo = fileInfoService.getByFilePath(decodedFilePath);
            if (fileInfo == null) {
                return AjaxResult.error(404, "文件不存在");
            }

            int pageCount = fileInfo.getPageCount();
            List<String> imageUrls = new ArrayList<>();

            // 生成所有页面的图片URL（修复URL格式，避免重复https://）
            String baseUrl = "https://" + aliOSSConfig.getBucketName() + "." + aliOSSConfig.getEndpoint() + "/";
            for (int i = 1; i <= pageCount; i++) {
                String imageUrl = baseUrl + decodedFilePath + "page-" + i + ".jpg";
                imageUrls.add(imageUrl);
            }

            Map<String, Object> data = new HashMap<>();
            data.put("imageUrls", imageUrls);
            data.put("pageCount", pageCount);


            return AjaxResult.success( data);
        } catch (Exception e) {
            log.error("获取图片列表失败", e);
            return AjaxResult.error(500, "获取图片列表失败：" + e.getMessage());
        }
    }








    /**
     * 预览文件
     *
     * @param response HTTP响应对象
     */
    @PostMapping(value = "/upload/preview")
    @ApiOperation("文件预览")
    public void showPresentation(HttpServletResponse response, @RequestParam("filePath") String filePath) throws IOException {
        try {
            System.out.println("filePath:"+filePath);
            String bucketName=aliOSSConfig.getBucketName();
            String objectKey = filePath.substring(filePath.lastIndexOf("/") + 1);
            // 创建OSSClient实例
            OSS ossClient = new OSSClientBuilder().build(aliOSSConfig.getEndpoint(), aliOSSConfig.getAccessKeyId(), aliOSSConfig.getAccessKeySecret());

            // 检查文件是否存在
            if (!ossClient.doesObjectExist(bucketName, objectKey)) {
                throw new FileNotFoundException("文件不存在：" + filePath);
            }

            // 获取文件输入流
            OSSObject ossObject = ossClient.getObject(bucketName, objectKey);
            InputStream inputStream = ossObject.getObjectContent();

            // 设置响应的内容类型
            String contentType;
            if (objectKey.endsWith(".pptx")) {
                contentType = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
            } else if (objectKey.endsWith(".ppt")) {
                contentType = "application/vnd.ms-powerpoint";
            } else if (objectKey.endsWith(".pdf")) {  // 添加对 PDF 文件的支持
                contentType = "application/pdf";
            } else {
                throw new IllegalArgumentException("不支持的文件类型：" + filePath);
            }
            response.setContentType(contentType);
            response.setHeader("Content-Disposition", "inline; filename=" + objectKey);

            OutputStream outputStream = response.getOutputStream();
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
            outputStream.flush();

            // 关闭流
            outputStream.close();
            inputStream.close();

            // 关闭OSSClient
            ossClient.shutdown();
        } catch (FileNotFoundException e) {
            log.error("文件未找到：{}", filePath);
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            response.getWriter().write("文件未找到：" + filePath);
        } catch (com.aliyun.oss.OSSException e) {
            log.error("OSS访问异常：", e);
            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
            response.getWriter().write("OSS访问异常：" + e.getMessage());
        } catch (IOException e) {
            log.error("预览文件异常：", e);
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            response.getWriter().write("预览文件异常：" + e.getMessage());
        }
    }





    @PostMapping("/upload")
    public Result upload(MultipartFile file) throws IOException {
        log.info("文件上传，文件名:{}", file.getOriginalFilename());
        // 调用阿里云oss工具类进行上传
        String url = aliOSSUtils.upload(file);
        log.info("文件上传完成，文件访问的url：{}", url);
        return Result.success(url);
    }

    /**
     * 上传指定格式的文件到阿里云OSS
     *
     * @param file
     * @return
     */
    @PostMapping(value = "/upload/Pdf")
    @ApiOperation("上传pdf文档")
    public Result uploadSpecificFile(MultipartFile file) {
        // 文件名
        String originalFileName = file.getOriginalFilename();

        if (originalFileName == null || originalFileName.isEmpty() || !isSupportedFileType(originalFileName)) {
            return Result.error("文件格式不正确！");
        }

        try {
            MultipartFile pdfFile;
            if (isImageFile(originalFileName)) {
                // 将图像文件转换为PDF
                pdfFile = convertImageToPdf(file);
            } else {
                pdfFile = file;
            }

            // 调用阿里云oss工具类进行上传
            String url = aliOSSUtils.uploadAppend(pdfFile,true);
            log.info("上传文件成功，文件访问的url：{}", url);
            return Result.success(url);
        } catch (Exception e) {
            log.error("上传文件异常：", e);
            return Result.error("上传文件失败！");
        }
    }

    /**
     * 检查文件是否为支持的格式
     *
     * @param fileName 文件名
     * @return 是否支持
     */
    private boolean isSupportedFileType(String fileName) {
        String extension = getExtension(fileName).toLowerCase();
        return extension.equals("pdf") || extension.equals("jpg") || extension.equals("jpeg") || extension.equals("png");
    }

    /**
     * 获取文件扩展名
     *
     * @param fileName 文件名
     * @return 扩展名
     */
    private String getExtension(String fileName) {
        if (fileName == null || fileName.isEmpty()) {
            return "";
        }
        int lastDotIndex = fileName.lastIndexOf('.');
        if (lastDotIndex == -1) {
            return ""; // 文件名中没有点，返回空字符串
        }
        return fileName.substring(lastDotIndex + 1);
    }

    /**
     * 检查文件是否为图像文件
     *
     * @param fileName 文件名
     * @return 是否为图像文件
     */
    private boolean isImageFile(String fileName) {
        String extension = getExtension(fileName).toLowerCase();
        return extension.equals("jpg") || extension.equals("jpeg") || extension.equals("png");
    }

    /**
     * 将图像文件转换为PDF文件
     *
     * @param imageFile 图像文件
     * @return 转换后的PDF文件
     * @throws IOException
     * @throws Exception
     */
    private MultipartFile convertImageToPdf(MultipartFile imageFile) throws IOException {
        log.info("开始将图片转换为PDF: {}", imageFile.getOriginalFilename());
        try (InputStream inputStream = imageFile.getInputStream();
             ByteArrayOutputStream baos = new ByteArrayOutputStream()) {

            PdfWriter writer = new PdfWriter(baos);
            PdfDocument pdfDoc = new PdfDocument(writer);
            Document document = new Document(pdfDoc);

            Image img = new Image(ImageDataFactory.create(inputStream.readAllBytes()));
            document.add(img);
            document.close();

            byte[] pdfBytes = baos.toByteArray();
            String newFileName = imageFile.getOriginalFilename().replaceFirst("[.][^.]+$", ".pdf");
            log.info("图片已成功转换为PDF: {}", newFileName);
            return new MockMultipartFile(newFileName, newFileName, "application/pdf", pdfBytes);
        } catch (IOException e) {
            log.error("图片转换为PDF失败: {}", imageFile.getOriginalFilename(), e);
            throw e;
        }
    }



    @PostMapping("/upload/appendPdf")
    @ApiOperation("pdf文件追加上传")
    public Result appendPdf(@RequestParam("filePath") String filePath, @RequestParam("fileToAppend") MultipartFile fileToAppend) {
        log.info("开始处理PDF追加上传，原文件路径: {}", filePath);

        String endpoint = aliOSSConfig.getEndpoint();
        String accessKeyId = aliOSSConfig.getAccessKeyId();
        String accessKeySecret = aliOSSConfig.getAccessKeySecret();
        String bucketName = aliOSSConfig.getBucketName();

        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        try {
            if (!ossClient.doesBucketExist(bucketName)) {
                ossClient.createBucket(bucketName);
                log.info("Bucket {} 不存在，已创建。", bucketName);
            }

            String objectKey = filePath.substring(filePath.lastIndexOf("/") + 1);

            // 处理上传的文件
            MultipartFile pdfToAppend = fileToAppend;
            if (isImageFile(fileToAppend.getOriginalFilename())) {
                log.info("上传的文件是图片，正在转换为PDF");
                pdfToAppend = convertImageToPdf(fileToAppend);
            }

            if (!"pdf".equals(getExtension(pdfToAppend.getOriginalFilename()).toLowerCase())) {
                log.error("上传文件不是PDF格式");
                return Result.error("上传文件必须是PDF或可转换为PDF的图片格式");
            }

            // 从OSS获取原始PDF文件
            OSSObject originalPdfObject = ossClient.getObject(bucketName, objectKey);
            InputStream originalPdfStream = originalPdfObject.getObjectContent();

            // 合并PDF
            String tempMergedPdfPath = System.getProperty("java.io.tmpdir") + File.separator + "mergedFile.pdf";
            try (InputStream additionalPdfStream = pdfToAppend.getInputStream()) {
                PdfMerger.mergePdfs(originalPdfStream, additionalPdfStream, tempMergedPdfPath);
            }

            // 上传合并后的文件到OSS
            File mergedFile = new File(tempMergedPdfPath);
            try (InputStream mergedFileStream = new FileInputStream(mergedFile)) {
                ObjectMetadata meta = new ObjectMetadata();
                meta.setContentType("application/pdf");
                ossClient.putObject(bucketName, objectKey, mergedFileStream, meta);
                log.info("文件 {} 追加成功并上传到OSS", objectKey);
            }

            // 删除临时文件
            if (!mergedFile.delete()) {
                log.warn("无法删除临时文件: {}", tempMergedPdfPath);
            }

            return Result.success("PDF追加成功");
        } catch (Exception e) {
            log.error("处理PDF文件出错", e);
            return Result.error("PDF追加失败: " + e.getMessage());
        } finally {
            ossClient.shutdown();
        }
    }


    @PostMapping("/deletePdfPage")
    @ApiOperation("删除PDF中的特定页面")
    public Result deletePdfPage(@RequestParam("filePath") String filePath, @RequestParam("pageNumber") int pageNumber) {
        log.info("开始删除PDF页面，文件路径: {}, 页码: {}", filePath, pageNumber);

        String bucketName = aliOSSConfig.getBucketName();
        String objectKey = filePath.substring(filePath.lastIndexOf("/") + 1);

        OSS ossClient = new OSSClientBuilder().build(aliOSSConfig.getEndpoint(), aliOSSConfig.getAccessKeyId(), aliOSSConfig.getAccessKeySecret());

        try {
            // 从OSS获取PDF文件
            OSSObject ossObject = ossClient.getObject(bucketName, objectKey);
            InputStream inputStream = ossObject.getObjectContent();

            // 使用PDFBox加载PDF
            PDDocument document = PDDocument.load(inputStream);

            // 检查页码是否有效
            if (pageNumber < 1 || pageNumber > document.getNumberOfPages()) {
                return Result.error("无效的页码");
            }

            // 删除指定页面
            document.removePage(pageNumber - 1);  // PDFBox使用0基索引

            // 将修改后的PDF保存到字节数组
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            document.save(baos);
            document.close();

            // 将修改后的PDF上传回OSS
            byte[] updatedPdfBytes = baos.toByteArray();
            ossClient.putObject(bucketName, objectKey, new ByteArrayInputStream(updatedPdfBytes));

            log.info("成功删除PDF页面并更新OSS中的文件");
            return Result.success("成功删除PDF页面");
        } catch (Exception e) {
            log.error("删除PDF页面时发生错误", e);
            return Result.error("删除PDF页面失败: " + e.getMessage());
        } finally {
            ossClient.shutdown();
        }
    }

    @PostMapping("/deleteFile")
    @ApiOperation("删除OSS中的文件")
    public Result deleteFile(@RequestParam("filePath") String filePath) {
        log.info("开始删除OSS中的文件，文件路径: {}", filePath);

        String bucketName = aliOSSConfig.getBucketName();
        String objectKey = filePath.substring(filePath.lastIndexOf("/") + 1);

        OSS ossClient = new OSSClientBuilder().build(aliOSSConfig.getEndpoint(), aliOSSConfig.getAccessKeyId(), aliOSSConfig.getAccessKeySecret());

        try {
            // 检查文件是否存在
            if (!ossClient.doesObjectExist(bucketName, objectKey)) {
                return Result.error("文件不存在：" + filePath);
            }

            // 删除文件
            ossClient.deleteObject(bucketName, objectKey);
            log.info("文件 {} 已成功删除", objectKey);

            return Result.success("文件删除成功");
        } catch (OSSException | ClientException e) {
            log.error("删除文件时发生错误", e);
            return Result.error("删除文件失败: " + e.getMessage());
        } finally {
            ossClient.shutdown();
        }
    }


}


